#include "Utils.h"
#include <fstream>
#include <algorithm>
using namespace std;

#include <stdlib.h>
#include <string.h>

#include <GL/glew.h>

#include "shader.h"

GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path)
{
	// Create the shaders
	GLuint VertexShaderID = CreateVertexShader(vertex_file_path);
	GLuint FragmentShaderID = CreateFragmentShader(fragment_file_path);

	return LinkProgram(VertexShaderID, FragmentShaderID);
}

GLuint CreateVertexShader(const char* p_vertex_file_path)
{
	GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);

	// Read the Vertex Shader code from the file
	std::string VertexShaderCode;
	std::ifstream VertexShaderStream(p_vertex_file_path, std::ios::in);
	if(VertexShaderStream.is_open())
	{
		std::string Line = "";
		while(getline(VertexShaderStream, Line))
			VertexShaderCode += "\n" + Line;
		VertexShaderStream.close();
	}else
	{
		printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", p_vertex_file_path);
		return 0;
	}

	// Compile Vertex Shader
	LOG("Compiling shader : %s\n", p_vertex_file_path);
	char const * VertexSourcePointer = VertexShaderCode.c_str();
	glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
	glCompileShader(VertexShaderID);

	GLint Result = GL_FALSE;
	int InfoLogLength;

	// Check Vertex Shader
	glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);

	if(Result == GL_TRUE)
		LOG("Success loading vertex shader %s\n", p_vertex_file_path);
	else
	{
		LOG("Fail loading vertex shader %s\n", p_vertex_file_path);

		if (InfoLogLength > 0)
		{
			LOG("InfoLogLength = %d", InfoLogLength);
			std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
			glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
			LOG("%s\n", &VertexShaderErrorMessage[0]);
		}
	}

	return VertexShaderID;
}

GLuint CreateFragmentShader(const char* p_fragment_file_path)
{
	GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

	// Read the Fragment Shader code from the file
	std::string FragmentShaderCode;
	std::ifstream FragmentShaderStream(p_fragment_file_path, std::ios::in);
	if(FragmentShaderStream.is_open())
	{
		std::string Line = "";
		while(getline(FragmentShaderStream, Line))
			FragmentShaderCode += "\n" + Line;
		FragmentShaderStream.close();
	}

	GLint Result = GL_FALSE;
	int InfoLogLength;

	// Compile Fragment Shader
	LOG("Compiling shader : %s\n", p_fragment_file_path);
	char const * FragmentSourcePointer = FragmentShaderCode.c_str();
	glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
	glCompileShader(FragmentShaderID);

	// Check Fragment Shader
	glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	if(Result == GL_TRUE)
		LOG("Success compiling fragment shader %s\n", p_fragment_file_path);
	else
	{
		LOG("Fail compiling fragment shader %s\n", p_fragment_file_path);

		if (InfoLogLength > 0)
		{
		
			std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
			glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
			LOG("%s\n", &FragmentShaderErrorMessage[0]);
		}
	}

	return FragmentShaderID;
}

GLuint LinkProgram(GLuint vertex_shader_id, GLuint fragment_shader_id)
{
	// Link the program
	LOG("Linking program\n");
	GLuint ProgramID = glCreateProgram();
	glAttachShader(ProgramID, vertex_shader_id);
	glAttachShader(ProgramID, fragment_shader_id);
	glLinkProgram(ProgramID);

	GLint Result = GL_FALSE;
	int InfoLogLength;

	// Check the program
	glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
	glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	if(InfoLogLength > 0)
	{
		std::vector<char> ProgramErrorMessage(InfoLogLength+1);
		glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
		LOG("%s\n", &ProgramErrorMessage[0]);
	}

	// Damien's modification for not deleting shader after loading
	//glDeleteShader(vertex_shader_id);
	//glDeleteShader(fragment_shader_id);

	return ProgramID;
}

